package com.cskaoyan.javse.oop3._0abstract._1basic;

/**
 * @description: 抽象类的特点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 *
 * 抽象类的特点:
 * 1.抽象类的声明/定义特点:
 * [访问权限修饰符] abstract class 类名{
 *     /类体
 * }
 * a.抽象类的类名,抽象类仍然是一个类,它的命名仍然需要遵循大驼峰的原则,
 *      在很多时候,定义抽象类时,喜欢在具体的类名前一个"Abstract",表示该类是一个抽象类
 *      比如AbstractPerson,AbstractAnimal 这是一个很好的设计,但不是强制的
 *
 * b.类在定义时,可以使用的修饰符很少,除了访问权限修饰符之外,几乎就只有final,abstract等少数
 *      但是final,abstract在修饰类时是冲突的,不能放在一起使用
 *      final是阻止继承,abstract是抽象类,如果不继承抽象类没有任何意义
 *
 * 2.抽象类的成员特点
 *      a.成员变量
 *          抽象类可以定义普通类中能够定义的所有成员变量,在这一点上,和普通类是一样的
 *
 *      b.成员方法,指的是有方法体,有具体实现的方法
 *          抽象类可以定义普通类中能够定义的所有成员方法,包括普通成员方法和静态成员方法,在这一点上,和普通类仍然是一样的
 *          抽象类虽然不能创建对象,但是它有子类,这些具体实现方法可以让子类继承,子类可以选择直接使用,也可以选择重写,选择的权力在子类手上(假如一个方法在抽象类的多个子类中都需要被使用,那么就可以提取到抽象类中)
 *          综上,普通类中能够定义的成员,在抽象类中都是可以定义的
 *
 *          思考: 抽象类允许没有抽象方法吗?
 *          允许,抽象类可以没有抽象方法,但是如果一个抽象类没有抽象方法,那么它就没有必要声明为抽象,直接声明为普通类就够了--> 抽象类存在的意义就是为了抽象方法
 *          如果不希望一个类能够创建对象,就把该类声明为抽象,这显然是不合适的,抽象类是作为祖先类存在的,主要目的不是为了不让它创建对象,如果有不创建对象的需求,应该私有化构造器
 *
 *      c.抽象方法
 *      [访问权限修饰符] abstract 返回值类型 方法名(形参列表);
 *      抽象方法最最重要的作用是起到"占位"的作用,任何普通类继承了该抽象类,都必须实现该抽象方法(强制的)
 *      如果子类不想实现抽象父类中的抽象方法,可以把子类设置为抽象类,抽象类就不需要实现抽象方法了
 *
 *      d.构造方法
 *      抽象类不能创建对象,那么它有没有构造器?
 *      构造器除了可以自己用,创建自己的对象时给成员变量赋值,还可以给子类用,在子类对象初始化过程中,可能会调用父类的构造方法给父类的成员变量赋值
 *
 * 综上所述,抽象类实际上和普通类能够定义的成员是一样的,普通类中有的东西它都有,只不过多了一个抽象方法
 *      以下:
 *              1.在不考虑创建对象的情况下,直接把一个类声明为abstract,是不会报错的
 *              2.在java中,任何类都有构造方法(类包括普通类和抽象类)
 *
 *      e.代码块
 *          静态代码块: 有
 *          构造代码块: 有
 *
 * - 抽象类的子类
 * 抽象类的子类有两种:
 *      1.普通类,普通类继承抽象类,必须实现所有的抽象方法
 *      2.抽象类,抽象子类不需要实现抽象方法,也可以自由选择实现
 *
 *
 * 抽象类能不能继承一个普通类呢? 是可以继承一个普通类的,当然实际中这种用法不多
 *
 *
 */
public  class Demo {
    public static void main(String[] args) {
        /*AbstractPerson ap;
        ap = new Teacher();
        ap.testAbstract();
        ap = new Student();
        ap.testAbstract();*/
        Student s = new Student(888, 666, "张三");
        System.out.println(s.a);
        //System.out.println(s.b);
        System.out.println(s.getB());
        System.out.println(s.name);
    }
}

//Illegal combination of modifiers: 'abstract' and 'final'
abstract class AbstractPerson {
    //定义成员变量
    int a;
    private int b = 10;
    static int c = 20;
    static final int D = 30;
    static {

    }
    {

    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    //定义成员方法
    public void test() {
        System.out.println("member!");
    }

    //定义静态成员方法
    public static void testStatic() {
        System.out.println("static!");
    }

    //定义抽象方法
    public abstract void testAbstract();
    //public abstract void testAbstract2();

    //定义构造方法
    public AbstractPerson(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public AbstractPerson() {
    }
}

//Class 'Teacher' must either be declared abstract or implement abstract method 'testAbstract()' in 'AbstractPerson'
class Teacher extends AbstractPerson {
    //三种方式重写父类的抽象方法
    //alt+回车 报错的类名
    //写父类方法名
    //alt+insert
    @Override
    public void testAbstract() {
        System.out.println("teacher");
    }
}

class Student extends AbstractPerson {

    String name;
    public Student(int a, int b, String name) {
        super(a, b);
        this.name = name;
    }

    public Student() {
    }

    @Override
    public void testAbstract() {
        System.out.println("student");
    }
}